""" gameEngine.py
    high-level tools to simplify pygame programming
    for Game Programming - The L-Line
    by Andy Harris, 2006
    Version 1.3 (11/11/07) - add state mechanism
        addState(stateName, image) to create a new state
        setState(stateName, image) to set the sprite to a state
        getState() return the current state name
    Version 1.2 - fix moveBy to call checkBounds correctly (was broken)
    Version 1.1 - incorporates drawTrace() method and
        replaces all default fonts with direct call to
        freesansbold.ttf (pygame's standard font.) This is done
        because py2exe doesn't seem to like system fonts under
        Windows.
"""

import math
from common import *
from config import *
import pygame
pygame.init()
log1 = getLogger("game",os.path.join(CENTER_LOG_PATH,"game.txt"))
class BasicSprite(pygame.sprite.Sprite):
    """ use this sprite when you want to
        directly control the sprite with dx and dy
        or want to extend in another direction than DirSprite
    """
    def __init__(self, scene):
        pygame.sprite.Sprite.__init__(self)
        self.screen = scene.screen
        self.image = pygame.Surface((25, 25))
        self.image.fill((255, 0, 0))
        self.rect = self.image.get_rect()
        self.x = 100
        self.y = 100
        self.dx = 0
        self.dy = 0

    def update(self):
        self.x += self.dx
        self.y += self.dy
        self.checkBounds()
        self.rect.center = (self.x, self.y)

    def checkBounds(self):
        scrWidth = self.screen.get_width()
        scrHeight = self.screen.get_height()

        if self.x > scrWidth:
            self.x = 0
        if self.x < 0:
            self.x = scrWidth
        if self.y > scrHeight:
            self.y = 0
        if self.y < 0:
            self.y = scrHeight

ACTION_STOP=1
ACTION_RUN=0
class SuperSprite(pygame.sprite.Sprite):
    """ An enhanced Sprite class
        expects a gameEngine.Scene class as its one parameter
        Use methods to change image, direction, speed
        Will automatically travel in direction and speed indicated
        Automatically rotates to point in indicated direction
        Five kinds of boundary collision
    """

    def __init__(self, name,scene,center=(100, 100)):
        pygame.sprite.Sprite.__init__(self)
        self.scene = scene
        self.screen = scene.screen
        self.name = name
        #create constants
        self.WRAP = 0
        self.BOUNCE = 1
        self.STOP = 2
        self.HIDE = 3
        self.CONTINUE = 4

        #create a default text image as a placeholder
        #This will usually be changed by a setImage call
        self.font = pygame.font.Font("freesansbold.ttf", 30)
        self.imageMaster = self.font.render(">sprite>", True, (0, 0,0), (0xFF, 0xFF, 0xFF))
        self.image = self.imageMaster
        self.rect = self.image.get_rect()
        self.eventList=[]
        #create properties
        #most will be changed through method calls
        self.x = center[0]
        self.y = center[1]
        self.dx = 0
        self.dy = 0
        self.dir = 0
        self.rotation = 0
        self.speed = 0
        self.maxSpeed = 5
        self.minSpeed = 0
        self.boundAction = self.WRAP
        self.pressed = False
        self.oldCenter = center
        self.states = {}
        self.currentState = "default"
        self.action = ACTION_RUN

    def setName(self,name):
        self.name = name

    def stop(self):
        self.action = ACTION_STOP

    def run(self):
        self.action = ACTION_RUN

    def update(self):

       # if self.action == ACTION_STOP:
       #     return

        self.oldCenter = self.rect.center
        self.checkEvents()
        self.__rotate()
        self.__calcVector()
        self.__calcPosition()
        self.checkBounds()
        self.rect.center = (self.x, self.y)

    def checkEvents(self):
        """ overwrite this method to add your own event code """
        pass

    def __rotate(self):
        """ PRIVATE METHOD
            change visual orientation based on
            rotation property.
            automatically called in update.
            change rotation property directly or with
            rotateBy(), setAngle() methods
        """
        oldCenter = self.rect.center
        self.oldCenter = oldCenter
        self.image = pygame.transform.rotate(self.imageMaster, self.rotation)
        self.rect = self.image.get_rect()
        self.rect.center = oldCenter

    def __calcVector(self):
        """ calculates dx and dy based on speed, dir
            automatically called in update
        """
        theta = self.dir / 180.0 * math.pi
        self.dx = math.cos(theta) * self.speed
        self.dy = math.sin(theta) * self.speed
        self.dy *= -1

    def __calcPosition(self):
        """ calculates the sprites position adding
            dx and dy to x and y.
            automatically called in update
        """
        self.x += self.dx
        self.y += self.dy

    def checkBounds(self):
        """ checks boundary and acts based on
            self.BoundAction.
            WRAP: wrap around screen (default)
            BOUNCE: bounce off screen
            STOP: stop at edge of screen
            HIDE: move off stage and wait
            CONTINUE: keep going at present course and speed

            automatically called by update
        """

        scrWidth = self.screen.get_width()
        scrHeight = self.screen.get_height()

        #create variables to simplify checking
        offRight = offLeft = offTop = offBottom = offScreen = False

        if self.x > scrWidth:
            offRight = True
        if self.x < 0:
            offLeft = True
        if self.y > scrHeight:
            offBottom = True
        if self.y < 0:
            offTop = True

        if offRight or offLeft or offTop or offBottom:
            offScreen = True

        if self.boundAction == self.WRAP:
            if offRight:
                self.x = 0
            if offLeft:
                self.x = scrWidth
            if offBottom:
                self.y = 0
            if offTop:
                self.y = scrHeight

        elif self.boundAction == self.BOUNCE:
            if offLeft or offRight:
                self.dx *= -1
            if offTop or offBottom:
                self.dy *= -1

            self.updateVector()
            self.rotation = self.dir

        elif self.boundAction == self.STOP:
            if offScreen:
                self.speed = 0

        elif self.boundAction == self.HIDE:
            if offScreen:
                self.speed = 0
                self.setPosition((-1000, -1000))

        elif self.boundAction == self.CONTINUE:
            pass

        else:
            # assume it's continue - keep going forever
            pass

    def setSpeed(self, speed):
        """ immediately sets the objects speed to the
            given value.
        """
        self.speed = speed

    def speedUp(self, amount):
        """ changes speed by the given amount
            Use a negative value to slow down
        """
        self.speed += amount
        if self.speed < self.minSpeed:
            self.speed = self.minSpeed
        if self.speed > self.maxSpeed:
            self.speed = self.maxSpeed

    def setAngle(self, dir):
        """ sets both the direction of motion
            and visual rotation to the given angle
            If you want to set one or the other,
            set them directly. Angle measured in degrees
        """
        self.dir = dir
        self.rotation = dir

    def turnBy (self, amt):
        """ turn by given number of degrees. Changes
            both motion and visual rotation. Positive is
            counter-clockwise, negative is clockwise
        """
        self.dir += amt
        if self.dir > 360:
            self.dir = amt
        if self.dir < 0:
            self.dir = 360 - amt
        self.rotation = self.dir

    def rotateBy(self, amt):
        """ change visual orientation by given
            number of degrees. Does not change direction
            of travel.
        """
        self.rotation += amt
        if self.rotation > 360:
            self.rotation = amt
        if self.rotation < 0:
            self.rotation = 360 - amt

    def setImage (self, image,isAlpha=True):
        """ loads the given file name as the master image
            default setting should be facing east.  Image
            will be rotated automatically """
        self.imageMaster = pygame.image.load(image)
        if isAlpha:
            self.imageMaster = self.imageMaster.convert_alpha()
        else:
            self.imageMaster = self.imageMaster.convert()


    def setDX(self, dx):
        """ changes dx value and updates vector """
        self.dx = dx
        self.updateVector()

    def addDX(self, amt):
        """ adds amt to dx, updates vector """
        self.dx += amt
        self.updateVector()

    def setDY(self, dy):
        """ changes dy value and updates vector """
        self.dy = dy
        self.updateVector()

    def addDY(self, amt):
        """ adds amt to dy and updates vector """
        self.dy += amt
        self.updateVector()

    def setComponents(self, components):
        """ expects (dx, dy) for components
            change speed and angle according to dx, dy values """

        (self.dx, self.dy) = components
        self.updateVector()

    def setBoundAction (self, action):
        """ sets action for boundary.  Values are
            self.WRAP (wrap around edge - default)
            self.BOUNCE (bounce off screen changing direction)
            self.STOP (stop at edge of screen)
            self.HIDE (move off-stage and stop)
            self.CONTINUE (move on forever)
            Any other value allows the sprite to move on forever
        """
        self.boundAction = action

    def setPosition (self, position):
        """ place the sprite directly at the given position
            expects an (x, y) tuple
        """
        (self.x, self.y) = position

    def moveBy (self, vector):
        """ move the sprite by the (dx, dy) values in vector
            automatically calls checkBounds. Doesn't change
            speed or angle settings.
        """
        (dx, dy) = vector
        self.x += dx
        self.y += dy
        self.checkBounds()

    def forward(self, amt):
        """ move amt pixels in the current direction
            of travel
        """

        #calculate dx dy based on current direction
        radians = self.dir * math.pi / 180
        dx = amt * math.cos(radians)
        dy = amt * math.sin(radians) * -1

        self.x += dx
        self.y += dy

    def addForce(self, amt, angle):
        """ apply amt of thrust in angle.
            change speed and dir accordingly
            add a force straight down to simulate gravity
            in rotation direction to simulate spacecraft thrust
            in dir direction to accelerate forward
            at an angle for retro-rockets, etc.
        """

        #calculate dx dy based on angle
        radians = angle * math.pi / 180
        dx = amt * math.cos(radians)
        dy = amt * math.sin(radians) * -1

        self.dx += dx
        self.dy += dy
        self.updateVector()

    def updateVector(self):
        #calculate new speed and angle based on dx, dy
        #call this any time you change dx or dy

        self.speed = math.sqrt((self.dx * self.dx) + (self.dy * self.dy))

        dy = self.dy * -1
        dx = self.dx

        radians = math.atan2(dy, dx)
        self.dir = radians / math.pi * 180

    def setSpeedLimits(self, max, min):
        """ determines maximum and minimum
            speeds you will allow through
            speedUp() method.  You can still
            directly set any speed you want
            with setSpeed() Default values:
                max: 10
                min: -3
        """
        self.maxSpeed = max
        self.minSpeed = min

    def dataTrace(self):
        """ utility method for debugging
            print major properties
            extend to add your own properties
        """
        print "x: %d, y: %d, speed: %.2f, dir: %.f, dx: %.2f, dy: %.2f" % \
              (self.x, self.y, self.speed, self.dir, self.dx, self.dy)

    def mouseDown(self):
        """ boolean function. Returns True if the mouse is
            clicked over the sprite, False otherwise
        """
        self.pressed = False
        if pygame.mouse.get_pressed() == (1, 0, 0):
            if self.rect.collidepoint(pygame.mouse.get_pos()):
                self.pressed = True
        return self.pressed

    def clicked(self):
        """ Boolean function. Returns True only if mouse
            is pressed and released over sprite

        released = False
        if self.pressed:
            if pygame.mouse.get_pressed() == (0, 0, 0):
                if self.rect.collidepoint(pygame.mouse.get_pos()):
                    released = True
            return released
        """
        released = False
        raise Exception,"do not use clicked any more,try check"
        return released

    def OnClick(self,event):
        log1.error("not implemented OnClick")

    def collidesWith(self, target):
        """ boolean function. Returns True if the sprite
            is currently colliding with the target sprite,
            False otherwise
        """
        collision = False
        if self.rect.colliderect(target.rect):
            collision = True
        return collision

    def collidesGroup(self, target):
        """ wrapper for pygame.sprite.collideany
            simplifies checking sprite - group collisions
            returns result of collision check (sprite from group
            that was hit or None)
        """
        collision = pygame.sprite.spritecollideany(self, target)
        return collision

    def distanceTo(self, point):
        """ returns distance to any point in pixels
            can be used in circular collision detection
        """
        (pointx, pointy) = point
        dx = self.x - pointx
        dy = self.y - pointy

        dist = math.sqrt((dx * dx) + (dy * dy))
        return dist

    def dirTo(self, point):
        """ returns direction (in degrees) to
            a point """

        (pointx, pointy) = point
        dx = self.x - pointx
        dy = self.y - pointy
        dy *= -1

        radians = math.atan2(dy, dx)
        dir = radians * 180 / math.pi
        dir += 180
        return dir

    def drawTrace(self, color=(0x00, 0x00, 0x00)):
        """ traces a line between previous position
            and current position of object
        """
        pygame.draw.line(self.scene.background, color, self.oldCenter,
                         self.rect.center, 3)
        self.screen.blit(self.scene.background, (0, 0))

    def addState(self, stateName, stateImageFile):
        """ Creates a new sprite state with the associated name
            and image. Useful to build multi-state sprites.
        """
        #load the image
        tempImage = pygame.image.load(stateImageFile)
        tempImage.convert()
        self.states[stateName] = tempImage

    def setState(self, stateName):
        """ attempts to set the sprite to the indicated state
            (image)
        """
        self.imageMaster = self.states[stateName]
        self.rect = self.imageMaster.get_rect()
        self.currentState = stateName

    def getState(self):
        """ returns the current state name
            (default if no states have been explicitly set)
        """
        return self.currentState

class MouseEvent(object):

    def __init__(self,type,buttons,pos):
        self.type = type
        self.buttons = buttons
        self.pos = pos

class Scene(object):
    """ encapsulates the IDEA / ALTER framework
        properties:
        sprites - a list of sprite objects
            that forms the primary sprite group
        background - the background surface
        screen - the display screen

        it's generally best to add all sprites
        as attributes, so they can have access
        to each other if needed
    """

    def __init__(self,size=(640,480),img=None):
        """ initialize the game engine
            set up a sample sprite for testing
        """
        pygame.init()
        self.screen = pygame.display.set_mode(size)
        if img:
            self.background = pygame.image.load(img).convert()
        else:
            self.background = pygame.Surface(self.screen.get_size())
            self.background.fill((0, 0, 0))
        self.sprites = []
        self.groups = []
        pygame.event.set_blocked(MOUSEMOTION)
        self.activeSprite = None
        self.activeDest   = None
        """
        self.sampleSprite = SuperSprite(self)
        self.sampleSprite.setSpeed(3)
        self.sampleSprite.setAngle(0)
        self.sampleSprite.boundAction = self.sampleSprite.WRAP
        """


    def start(self):
        """ sets up the sprite groups
            begins the main loop
        """
        self.mainSprites = pygame.sprite.OrderedUpdates(self.sprites)
        self.groups.append(self.mainSprites)

        self.screen.blit(self.background, (0, 0))
        self.clock = pygame.time.Clock()
        self.keepGoing = True
        while self.keepGoing:
            self.__mainLoop()
            
        self.exit()

    def exit(self):
        pygame.quit()
        
    def stop(self):
        """stops the loop"""
        self.keepGoing = False

    def __mainLoop(self):
        """ manage all the main events
            automatically called by start
        """
        self.clock.tick(30)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.keepGoing = False
            self.doEvents(event)

        self.update()
        for group in self.groups:
            group.clear(self.screen, self.background)
            group.update()
            group.draw(self.screen)

        pygame.display.flip()
        #pygame.display.update()
    def makeSpriteGroup(self, sprites):
        """ create a group called groupName
            containing all the sprites in the sprites
            list.  This group will be added after the
            sprites group, and will automatically
            clear, update, and draw
        """
        tempGroup = pygame.sprite.OrderedUpdates(sprites)
        return tempGroup

    def addGroup(self, group):
        """ adds a sprite group to the groups list for
            automatic processing
        """
        self.groups.append(group)

    def doEvents(self, event):
        """ overwrite this method to add your own events.
            works like normal event handling, passes event
            object
        """
        if event.type==MOUSEBUTTONDOWN:
            #find the focus
            focus = False
            pos = pygame.mouse.get_pos()
            buttons = pygame.mouse.get_pressed()
            log1.debug("downpos=(%d,%d),btn=(%d,%d,%d)"%(pos[0],pos[1],buttons[0],buttons[1],buttons[2]))
            for sprite in self.sprites:#self.mainSprites.sprites():
                    log1.debug("sprite:name=%s,rect=(%d,%d,%d,%d),center=(%d,%d)"%(sprite.name,sprite.rect.left,sprite.rect.top,sprite.rect.right,sprite.rect.bottom,sprite.rect.centerx,sprite.rect.centery))
                    if sprite.rect.collidepoint(pos):
                        event2 = MouseEvent(MOUSEBUTTONDOWN,buttons,pos)
                        sprite.eventList.append(event2)
                        focus = True
                        log1.debug("click %s"%sprite.name)
                        self.activeSprite = sprite
                        break
            if not focus:
                self.OnClick(event)
                #self.activeSprite = None
                self.activeDest = pos
                if self.activeSprite:
                    self.activeSprite.activeDest = pos
                    
        elif self.activeSprite:
            if event.type==KEYDOWN:
                
                #angle
                if event.key == pygame.K_LEFT:
                    self.activeSprite.addDX(-0.5)
                elif event.key ==pygame.K_RIGHT:
                    self.activeSprite.addDX(0.5)
                elif event.key ==pygame.K_UP:
                    self.activeSprite.addDY(-0.5)
                elif event.key ==pygame.K_DOWN:
                    self.activeSprite.addDY(0.5)
                #speed
                elif event.key ==pygame.K_EQUALS:
                    self.activeSprite.speedUp(0.5)
                elif event.key ==K_MINUS:
                    self.activeSprite.speedUp(-0.5) 
                #stop/start
                elif event.key ==pygame.K_g:#go
                    dir= self.activeSprite.dirTo(self.activeDest)
                    self.activeSprite.setAngle(dir)
                    self.activeSprite.setSpeed(1)
                    log1.debug("move to (%d,%d)"%(self.activeDest[0],self.activeDest[1]))
                elif event.key ==pygame.K_s:#stop
                    self.activeSprite.setSpeed(0)
                elif event.key ==pygame.K_m:#move to
                    self.activeSprite.setPosition(self.activeDest)
                    self.activeSprite.setSpeed(0)
                else:
                    self.activeSprite.eventList.append(event)    
                
    def OnClick(self,event):
        raise NotImplementedError,"implement onclick please"

    def update(self):
        """ happens once per frame, after event parsing.
            Overwrite to add your own code, esp event handling
            that doesn't require event obj. (pygame.key.get_pressed,
            pygame.mouse.get_pos, etc)
            Also a great place for collision detection
            Number Huang: herein, check the mouse event and post to the sprite
        """
        pass

    def setCaption(self, title):
        """ set's the scene's title text """
        pygame.display.set_caption(title)

ITEM_HEIGHT = 32
class Label(pygame.sprite.Sprite):
    """ a basic label
        properties:
            font: font to use
            text: text to display
            fgColor: foreground color
            bgColor: background color
            center: position of label's center
            size: (width, height) of label
    """

    def __init__(self, fontName = "freesansbold.ttf",center=(100, 100),size=(150, 30)):
        pygame.sprite.Sprite.__init__(self)
        self.font = pygame.font.Font(fontName, 20)
        self.text = ""
        self.fgColor = ((0x00, 0x00, 0x00))
        self.bgColor = ((0xFF, 0xFF, 0xFF))
        self.center = center
        self.size = size

    def update(self):
        self.image = pygame.Surface(self.size)
        self.image.fill(self.bgColor)
        fontSurface = self.font.render(self.text, True, self.fgColor, self.bgColor)
        #center the text
        xPos = (self.image.get_width() - fontSurface.get_width())/2

        self.image.blit(fontSurface, (xPos, 0))
        self.rect = self.image.get_rect()
        self.rect.center = self.center

class Button(Label):
    """ a button based on the label
        same properties as label +
        active: True if user is clicking on sprite
                False if user is not currently clicking
        clicked: True when user releases mouse over a
                 currently active button
    """

    def __init__(self,center1=(100, 100),size1=(150, 30)):
        Label.__init__(self,center=center1,size=size1)
        self.active = False
        self.clicked = False
        self.bgColor = (0xCC, 0xCC, 0xCC)

    def update(self):
        Label.update(self)

        self.clicked = False

        #check for mouse input
        if pygame.mouse.get_pressed() == (1, 0, 0):
            if self.rect.collidepoint(pygame.mouse.get_pos()):
                self.active = True

        #check for mouse release
        if self.active == True:
            if pygame.mouse.get_pressed() == (0, 0, 0):
                self.active = False
                if self.rect.collidepoint(pygame.mouse.get_pos()):
                    self.clicked = True

class Button2(Button):
    """ a button based on the label
        same properties as label +
        active: True if user is clicking on sprite
                False if user is not currently clicking
        clicked: True when user releases mouse over a
                 currently active button
    """

    def __init__(self,owner,center1=(100, 100),size1=(150, 30)):
        super(Button2,self).__init__(center1,size1)
        self.owner = owner
        #self.rect2 = pygame.Rect(self.center,self.size)

    def update(self):
        Label.update(self)

        self.clicked = False
        #self.rect = self.rect2
        #check for mouse input
        for event in self.owner.eventList:

            log1.debug("button pos=(%d,%d,%d,%d)"%(self.rect.left,self.rect.top,self.rect.right,self.rect.bottom))
            if event.type == MOUSEBUTTONDOWN:
                if event.buttons[0] == 1:
                    if self.rect.collidepoint(event.pos):
                         self.clicked = True

class Scroller(Button):
    """ like a button, but has a numeric value that
        can be decremented by clicking on left half
        and incremented by clicking on right half.
        new atributes:
            value: the scroller's numeric value
            minValue: minimum value
            maxValue: maximum value
            increment: How much is added or subtracted
            format: format of string interpolation
    """

    def __init__(self):
        Button.__init__(self)
        self.minValue = 0
        self.maxValue = 10
        self.increment = 1
        self.value = 5
        self.format = "<<  %.2f  >>"

    def update(self):
        Button.update(self)
        if self.active:
            (mousex, mousey) = pygame.mouse.get_pos()
            if mousex < self.rect.centerx:
                self.value -= self.increment
                if self.value < self.minValue:
                    self.value = self.minValue
            else:
                self.value += self.increment
                if self.value > self.maxValue:
                    self.value = self.maxValue

        self.text = self.format % self.value

class MultiLabel(pygame.sprite.Sprite):
    """ accepts a list of strings, creates a multi-line
        label to display text
        same properties as label except textLines
        is a list of strings. There is no text
        property.
        Set the size manually. Vertical size should be at
        least 30 pixels per line (with the default font)
    """

    def __init__(self,pos=(100,100),size=(150, 100)):
        pygame.sprite.Sprite.__init__(self)
        self.textLines = ["This", "is", "sample", "text"]
        self.font = pygame.font.Font("freesansbold.ttf", 12)
        self.fgColor = ((0x00, 0x00, 0x00))
        self.bgColor = ((0xFF, 0xFF, 0xFF))
        self.center = pos
        self.size = size

    def update(self):
        self.image = pygame.Surface(self.size)
        self.image.fill(self.bgColor)
        numLines = len(self.textLines)
        vSize = ITEM_HEIGHT#self.image.get_height() / numLines

        for lineNum in range(numLines):
            currentLine = self.textLines[lineNum]
            fontSurface = self.font.render(currentLine, True, self.fgColor, self.bgColor)
            #center the text
            xPos = 0#(self.image.get_width() - fontSurface.get_width())/2
            yPos = lineNum * vSize
            self.image.blit(fontSurface, (xPos, yPos))

        self.rect = self.image.get_rect()
        self.rect.center = self.center

ETM_DIALOG = 0
ETM_MENU = 1
MENU_HEIGHT = 240
MENU_WIDTH = 240
def getTxtSerface(string, rect, font=pygame.font.Font("freesansbold.ttf", 12), text_color=(0,0,0), background_color=(0xff,0xff,0xff), justification=0):
    """Returns a surface containing the passed text string, reformatted
    to fit within the given rect, word-wrapping as necessary. The text
    will be anti-aliased.

    Takes the following arguments:

    string - the text you wish to render. \n begins a new line.
    font - a Font object
    rect - a rectstyle giving the size of the surface requested.
    text_color - a three-byte tuple of the rgb value of the
                 text color. ex (0, 0, 0) = BLACK
    background_color - a three-byte tuple of the rgb value of the surface.
    justification - 0 (default) left-justified
                    1 horizontally centered
                    2 right-justified

    Returns the following values:

    Success - a surface object with the text rendered onto it.
    Failure - raises a TextRectException if the text won't fit onto the surface.
    """



    final_lines = []

    requested_lines = string.splitlines()

    # Create a series of lines that will fit on the provided
    # rectangle.

    for requested_line in requested_lines:
        if font.size(requested_line)[0] > rect.width:
            words = requested_line.split(' ')
            # if any of our words are too long to fit, return.
            for word in words:
                if font.size(word)[0] >= rect.width:
                    raise Exception, "The word " + word + " is too long to fit in the rect passed."
            # Start a new line
            accumulated_line = ""
            for word in words:
                test_line = accumulated_line + word + " "
                # Build the line while the words fit.
                if font.size(test_line)[0] < rect.width:
                    accumulated_line = test_line
                else:
                    final_lines.append(accumulated_line)
                    accumulated_line = word + " "
            final_lines.append(accumulated_line)
        else:
            final_lines.append(requested_line)

    # Let's try to write the text out on the surface.

    surface = pygame.Surface(rect.size)
    surface.fill(background_color)

    accumulated_height = 0
    for line in final_lines:
        if accumulated_height + font.size(line)[1] >= rect.height:
            raise Exception, "Once word-wrapped, the text string was too tall to fit in the rect."
        if line != "":
            tempsurface = font.render(line, 1, text_color)
            if justification == 0:
                surface.blit(tempsurface, (0, accumulated_height))
            elif justification == 1:
                surface.blit(tempsurface, ((rect.width - tempsurface.get_width()) / 2, accumulated_height))
            elif justification == 2:
                surface.blit(tempsurface, (rect.width - tempsurface.get_width(), accumulated_height))
            else:
                raise Exception, "Invalid justification argument: " + str(justification)
        accumulated_height += font.size(line)[1]

    return surface

class MultiLabel2(pygame.sprite.Sprite):
    """ accepts a list of strings, creates a multi-line
        label to display text
        same properties as label except textLines
        is a list of strings. There is no text
        property.
        Set the size manually. Vertical size should be at
        least 30 pixels per line (with the default font)
    """

    def __init__(self,info,pos=(100,100),size=(150, 100)):
        pygame.sprite.Sprite.__init__(self)
        self.center = pos
        self.size = size
        self.rect = pygame.Rect((0,0,size[0],size[1]))
        self.rect.center = self.center
        self.image = getTxtSerface(info,self.rect)
    def update(self):
        pass


class PopupMenu(SuperSprite):
    """
        class comment
    """

    def __init__(self,name,scene,pos=(120,120),size=(MENU_WIDTH,MENU_HEIGHT)):

        super(PopupMenu,self).__init__(name,scene)
        self.center = pos
        self.font = pygame.font.Font("freesansbold.ttf", 20)
        self.fgColor = ((0x00, 0x00, 0x00))
        self.bgColor = ((0xFF, 0xFF, 0xFF))
        self.resize(size)
        self.ctrlList=[]
        self.type = ETM_MENU

    def resize(self,newSize):
        self.size = newSize
        self.image = pygame.Surface(self.size)
        self.rect = self.image.get_rect()
        self.rect.center = self.center
        self.image.fill(self.bgColor)

    def addInfo(self,info):

        lines = info.splitlines()
        pos   = self.center
        size  = self.size
        item  = MultiLabel2(info,pos,size)
        self.ctrlList.append((item,None,None,self.size[1]))

    def addOneItem(self,title,action=None,params=None,size=None):
        idx = len(self.ctrlList)
        pos = (self.rect.left + self.size[0]/2,self.rect.top +idx*ITEM_HEIGHT + ITEM_HEIGHT/2)
        size = (self.size[0],ITEM_HEIGHT)
        item = Button2(self,pos,size)
        item.text = title
        self.ctrlList.append((item,action,params,ITEM_HEIGHT))

    def addOneDialog(self,info,OKAction=None,CancelAction=None,size=None):

        lines = info.splitlines()
        height = len(lines)*ITEM_HEIGHT
        if height + ITEM_HEIGHT >MENU_HEIGHT:
            self.resize((self.size[0],height+ ITEM_HEIGHT))
        pos = (self.rect.left + self.size[0]/4,self.rect.top + ITEM_HEIGHT/2)
        size = (self.size[0]/2,ITEM_HEIGHT)
        item = Button2(self,pos,size)
        item.text = "OK"
        self.ctrlList.append((item,OKAction,None,ITEM_HEIGHT))

        pos = (self.rect.left + self.size[0]*0.75,self.rect.top + ITEM_HEIGHT/2)
        item = Button2(self,pos,size)
        item.text = "Cancel"
        self.ctrlList.append((item,CancelAction,None,ITEM_HEIGHT))
        self.type = ETM_DIALOG

        pos = (self.rect.left + self.size[0]/2,self.rect.top + ITEM_HEIGHT + height/2)
        size = (self.size[0],height)
        item = MultiLabel(pos,size)
        item.textLines = lines
        self.ctrlList.append((item,None,None,height))

    def update(self):

        self.rect.center = self.center
        height = 0
        for ctrl,action,params,height1 in self.ctrlList:
            ctrl.update()
            left = ctrl.rect.left - self.rect.left
            top  = ctrl.rect.top - self.rect.top
            self.image.blit(ctrl.image,(left,top))
            if isinstance(ctrl,Button) and ctrl.clicked:
                if action:
                    action(params)
                self.scene.deleteOneSprite(self)#hide the menu
            #height += height1
        self.eventList=[]
if __name__ == "__main__":
    # change this code to test various features of the engine
    # This code will not run when gameEngine is run as a module
    # (as it usually will be) This code only runs when gameEngine
    # is treated as an executable program...

    game = Scene()
    thing = SuperSprite(game)
    thing.setSpeed(5)
    thing.setBoundAction(thing.BOUNCE)
    thing.setAngle(230)
    game.sprites = [thing]

    game.start()